package net.cyue.easyconfiguration.yaml;

import net.cyue.easyconfiguration.api.IConfigurationResource;
import net.cyue.easyconfiguration.node.NodeType;
import net.cyue.util.ResourceUtil;
import net.cyue.util.StringUtil;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.*;

public class YAMLConfigurationResource implements IConfigurationResource {

    private final Map<String, Object> yamlData;
    private static final String PATH_SEPARATOR = ".";
    private static final String WILDCARD = "*";

    public YAMLConfigurationResource(File file) throws IOException {
        this(Files.newInputStream(file.toPath()));
    }

    public YAMLConfigurationResource(String yamlContent) {
        Yaml yaml = new Yaml();
        Object loadedData = yaml.load(yamlContent);
        this.yamlData = convertToMap(loadedData);
    }

    public YAMLConfigurationResource(InputStream inputStream) throws IOException {
        Yaml yaml = new Yaml();
        Object loadedData = yaml.load(inputStream);
        this.yamlData = convertToMap(loadedData);
    }

    public static YAMLConfigurationResource fromResource(String resourceName) throws IOException {
        InputStream inputStream = ResourceUtil.getResourceAsStream(resourceName);
        if (inputStream == null) {
            throw new IllegalArgumentException("Resource not found: " + resourceName);
        }
        return new YAMLConfigurationResource(inputStream);
    }

    @Override
    public NodeType getNodeType(String path) {
        Object value = get(path);
        if (value == null) {
            return NodeType.ANY;
        }

        if (value instanceof Map) {
            return NodeType.TABLE;
        } else if (
            value instanceof Object[] ||
            value.getClass().isArray()
        ) {
            return NodeType.ARRAY;
        } else if (value instanceof String) {
            return NodeType.STRING;
        } else if (value instanceof Number) {
            return NodeType.NUMBER;
        } else if (value instanceof Boolean) {
            return NodeType.BOOLEAN;
        } else {
            return NodeType.fromClass(value.getClass());
        }
    }

    @Override
    public List<String> getTableKeyList(String tablePath) {
        if (StringUtil.isBlank(tablePath) || WILDCARD.equals(tablePath.trim())) {
            return new ArrayList<>(yamlData.keySet());
        }

        Object value = get(tablePath);
        if (value instanceof Map) {
            return new ArrayList<>(((Map<String, ?>) value).keySet());
        }
        return Collections.emptyList();
    }

    @Override
    public Object get(String path) {
        if (StringUtil.isBlank(path)) {
            return convertToMapWithChildrenProcessed(yamlData);
        }

        String[] pathSegments = path.split("\\.");
        Object current = yamlData;

        for (String segment : pathSegments) {
            if (current instanceof Map) {
                current = ((Map<?, ?>) current).get(segment);
            } else if (current instanceof List && isNumeric(segment)) {
                current = getListElement(current, segment);
            } else if (current instanceof Object[] && isNumeric(segment)) {
                current = getArrayElement(current, segment);
            } else {
                return null;
            }

            if (current == null) {
                return null;
            }
        }

        return processValue(current);
    }

    @Override
    public String getString(String path) {
        Object value = get(path);
        return value != null ? value.toString() : null;
    }

    @Override
    public Number getNumber(String path) {
        Object value = get(path);
        if (value instanceof Number) {
            return (Number) value;
        }
        if (value instanceof String) {
            try {
                return Double.parseDouble((String) value);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public Boolean getBoolean(String path) {
        Object value = get(path);
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        if (value instanceof String) {
            return "true".equalsIgnoreCase((String) value);
        }
        return null;
    }

    @Override
    public Object[] getArray(String path) {
        Object value = get(path);
        if (value instanceof Object[]) {
            return (Object[]) value;
        }
        return new Object[0];
    }

    @Override
    public Map<String, Object> getTable(String path) {
        Object value = get(path);
        return convertToMap(value);
    }

    /**
     * 处理值对象，将List转换为数组，Map转换为处理后的Map
     */
    private Object processValue(Object value) {
        if (value instanceof List) {
            return listToArray((List<?>) value);
        } else if (value instanceof Map) {
            return convertToMapWithChildrenProcessed(value);
        }
        return value;
    }

    /**
     * 从列表中获取指定索引的元素
     */
    private Object getListElement(Object current, String segment) {
        try {
            int index = Integer.parseInt(segment);
            List<?> list = (List<?>) current;
            if (index >= 0 && index < list.size()) {
                return processValue(list.get(index));
            }
        } catch (NumberFormatException e) {
            // 索引格式错误，返回null
        }
        return null;
    }

    /**
     * 从数组中获取指定索引的元素
     */
    private Object getArrayElement(Object current, String segment) {
        try {
            int index = Integer.parseInt(segment);
            Object[] array = (Object[]) current;
            if (index >= 0 && index < array.length) {
                return processValue(array[index]);
            }
        } catch (NumberFormatException e) {
            // 索引格式错误，返回null
        }
        return null;
    }

    /**
     * 将List转换为Object数组，并处理其中的元素
     */
    private Object[] listToArray(List<?> list) {
        Object[] array = new Object[list.size()];
        for (int i = 0; i < list.size(); i++) {
            array[i] = processValue(list.get(i));
        }
        return array;
    }

    /**
     * 转换对象为Map，并处理所有子元素
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> convertToMapWithChildrenProcessed(Object value) {
        if (value instanceof Map) {
            Map<String, Object> resultMap = new HashMap<>();
            ((Map<String, Object>) value).forEach((key, val) ->
                    resultMap.put(key, processValue(val))
            );
            return resultMap;
        }
        return Collections.emptyMap();
    }

    /**
     * 将对象转换为Map，如果对象不是Map类型则返回空Map
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> convertToMap(Object value) {
        if (value instanceof Map) {
            return (Map<String, Object>) value;
        }
        return Collections.emptyMap();
    }

    /**
     * 检查字符串是否为数字
     */
    private boolean isNumeric(String str) {
        if (str == null || str.isEmpty()) {
            return false;
        }
        for (char c : str.toCharArray()) {
            if (!Character.isDigit(c)) {
                return false;
            }
        }
        return true;
    }
}
